<!--- START CUSTOM TAG UDFS --->
<cffunction name="cleanViewPath" access="private">
	<cfargument name="path" required="true" type="string">
	<!---
		a valid viewPath looks like ~ debug || myView/myOtherView
		this corresponds to a sub-directory of /view (e.g. view/debug || view/myView/myOtherView)
	--->

	<!--- only allow alphanumerics (technically too conservative but hey...) --->
	<cfset result = rereplace(arguments.path, "/^[0-9A-Za-z]+$/", "")>

	<!--- if the leading char is a / then strip it --->
	<cfif left(result, 1) EQ "/">
		<cfset result = right(arguments.path, len(arguments.path) - 1)>
	</cfif>

	<!--- if the trailing char is a / then strip it --->
	<cfif right(result, 1) EQ "/">
		<cfset result = left(arguments.path, len(arguments.path) - 1)>
	</cfif>

	<cfreturn result>
</cffunction>
<!---  --->
<cffunction name="setupController" access="private">
	<!---
		if the controller CFC exists then we load it into memory
		we use the session scope so it will be available to AJAX requests within this view
	--->
	<cfset session.set("controller", createObject("component", "#session.controllerPath#").init())>
	<cfset controllerMeta = getComponentMetadata("#session.controllerPath#")>

	<cfif isDefined("controllerMeta.functions")>
		<!---
			see what standard methods are in the controller
			note: auto-invoked controller functions take no arguments
				they are intended to handle form and request data and do general tasks
		--->
		<cfloop array="#controllerMeta.functions#" index="I">
			<cfswitch expression="#I.name#">
				<cfcase value="preView">	<!--- preView will run before the view is loaded --->
					<cfset session.context.preView = true>
				</cfcase>
				<cfcase value="preRequest">	<!--- preRequest runs after every request within this view (even AJAX/subViews) --->
					<cfset session.context.preRequest = true>
				</cfcase>
				<cfcase value="postRequest">	<!--- postRequest runs after every request within this view (even AJAX/subViews) --->
					<cfset session.context.postRequest = true>
				</cfcase>
				<cfcase value="postView">	<!--- postView runs after the view is loaded --->
					<cfset session.context.postView = true>
				</cfcase>
			</cfswitch>
		</cfloop>
	</cfif>
</cffunction>
<!---  --->
<cffunction name="setupDisplay" access="private">
	<cfset session.set("display", createObject("component", "#session.displayPath#").init())>
</cffunction>
<!--- END CUSTOM TAG UDFS --->

<!--- throw out if it's not implemented as a full tag --->
<cfif NOT thisTag.HasEndTag>
	<cfthrow detail="The CFmaker wrapper tag must be a full, closed tag and should surround all page content" message="The CFmaker tag is unclosed" type="Custom">
</cfif>

<!--- START SETUP ATTRIBUTE DEFAULTS --->
<cfparam name="attributes.viewPath" default="">
<!--- END ATTRIBUTE DEFAULT SETUP --->

<cfif thisTag.executionMode EQ "Start">
	<!--- PAGE START SETUP --->
	<cfif len(attributes.viewPath)>
		<cf_triggerEvent event="preView">

		<!--- if the CGI.path_info is provided we assume we're loading a view --->
		<cflock scope="Session" throwontimeout="true" timeout="7" type="exclusive">
			<!--- normally, I would use session.set, but for a block of writes we'll do this --->
			<cfset session.context = #structNew()#>
			<cfset session.context.preRequest = false>
			<cfset session.context.postRequest = false>
			<cfset session.context.preView = false>
			<cfset session.context.postView = false>

			<cfset session.view = cleanViewPath(attributes.viewPath)>

			<cfset session.viewPath = "#application.path#/view/#session.view#">

			<cfset session.controllerPath = "#application.dotPath#view.#session.view#.controller">
			<cfset session.controllerTemplate = replace("#application.path#/view/#session.view#/controller.cfc", "\", "/", "all")>

			<cfset session.displayPath = "#application.dotPath#view.#session.view#.display">
			<cfset session.displayTemplate = replace("#application.path#/view/#session.view#/display.cfc", "\", "/", "all")>
		</cflock>

		<cfif fileExists("#session.controllerTemplate#")>
			<cfset setupController()>
		</cfif>

		<cfif fileExists("#session.displayTemplate#")>
			<cfset setupDisplay()>
		</cfif>

		<cfif isDefined("session.context.preView") AND session.context.preView>
			<cfinvoke component="session.controller" method="preView">
		</cfif>

		<!--- now, for some HTML --->
			<cfoutput>
				<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
				<html>
					<head>
						<title>CFmaker</title>

						<link href="#application.URL#/app/css/jquery-ui-1.7.2.custom.css" rel="stylesheet">	<!--- optional --->
						<link href="#application.URL#/app/css/application.css" rel="stylesheet">
						<link href="#application.URL#/view/#session.view#/styles.css" rel="stylesheet">

						<cfajaximport>
						<cfajaxproxy cfc="#application.dotPath#app.appProxy" jsclassname="applicationProxy">
						<cfajaxproxy cfc="#application.dotPath#view.#session.view#.controller" jsclassname="controllerProxy">
						<cfajaxproxy cfc="#application.dotPath#view.#session.view#.display" jsclassname="displayProxy">

						<!---
							scripts loaded for every view, including full versions for development mode
							jquery core is required
							jquery-ui not required but is used in bundled views
								if you download a custom theme you can just copy/overwrite the CSS and images directory
								if you use a pre-rolled theme then you migh have to change the js filename in the script tag below

							obviously, it's up to the developer to provide a minified version of view scripts, or just use the full js
								try: http://closure-compiler.appspot.com/home
						--->

						<cfif application.developmentMode>
							<script language="JavaScript" src="#application.URL#/app/js/jquery-1.4.js" type="text/javascript"></script>
							<!--- mini version here...full version is not a single file, so... --->
							<script language="JavaScript" src="#application.URL#/app/js/jquery-ui-1.7.2.custom.min.js" type="text/javascript"></script>
							<!--- jquery-ui-1.7.2.custom.min.js --->
							<script language="JavaScript" src="#application.URL#/app/js/application.js" type="text/javascript"></script>
							<script language="JavaScript" src="#application.URL#/app/js/jquery.CFmaker.js" type="text/javascript"></script>
							<script language="JavaScript" src="#application.URL#/app/js/jquery.hotkeys.js" type="text/javascript"></script>
							<script language="JavaScript" src="#application.URL#/app/js/jquery.mousewheel.js" type="text/javascript"></script>
							<script language="JavaScript" src="#application.URL#/view/#session.view#/script.js" type="text/javascript"></script>
						<cfelse>
							<script language="JavaScript" src="#application.URL#/app/js/jquery-1.4.min.js" type="text/javascript"></script>
							<script language="JavaScript" src="#application.URL#/app/js/jquery-ui-1.7.2.custom.min.js" type="text/javascript"></script>
							<script language="JavaScript" src="#application.URL#/app/js/application.min.js" type="text/javascript"></script>
							<script language="JavaScript" src="#application.URL#/app/js/jquery.CFmaker.min.js" type="text/javascript"></script>
							<script language="JavaScript" src="#application.URL#/app/js/jquery.hotkeys.min.js" type="text/javascript"></script>
							<script language="JavaScript" src="#application.URL#/app/js/jquery.mousewheel.min.js" type="text/javascript"></script>
							<script language="JavaScript" src="#application.URL#/view/#session.view#/script.min.js" type="text/javascript"></script>
						</cfif>
					</head>

					<body>
			</cfoutput>
	<cfelse>
		<cfexit method="exittag">
	</cfif>

<cfelseif thisTag.executionMode EQ "End">
	<!--- PAGE END SETUP --->
	<cfif len(attributes.viewPath)>
					</body>
				</html>

		<cf_triggerEvent event="postView">
	<cfelse>
		<cfexit method="exittag">
	</cfif>
</cfif>